package genedit.controller.interfaceActions;

import genedit.controller.AddCommand;
import genedit.gui.GMainFrame;
import genedit.model.Workspace;
import genedit.model.graph.BreakPoint;
import genedit.model.graph.GraphElement;
import genedit.model.graph.Link;
import genedit.view.graph.Clipboard;
import genedit.view.graph.GraphDocumentView;
import genedit.view.graph.GraphWorkArea;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.KeyStroke;

/**
 * Akcija zadužena za nalepljivanje elemenata iz klipborda na radnu površinu
 * aktivnog dokumenta.
 * 
 * @author Nikola
 * @version 1.1 15/12/13
 */
public class GPasteA extends AbstractAction {

	private static final long serialVersionUID = 1L;

	private static GPasteA gPasteA = null;

	protected GPasteA() {
		putValue(NAME, "Paste");
		putValue(SHORT_DESCRIPTION, "Paste");
		putValue(SMALL_ICON, new ImageIcon("resources/icons/paste.png"));
		putValue(MNEMONIC_KEY, KeyEvent.VK_P);
		putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("control V"));
	}

	public static AbstractAction getInstance() {
		if (gPasteA == null)
			gPasteA = new GPasteA();
		return gPasteA;
	}

	private GraphDocumentView document;
	// Koordinate centra vizira aktivnog dokumenta
	private double x;
	private double y;

	/**
	 * Metoda sračunava centar vizira dokumenta na koji se nalepljuju elementi.
	 * Nakon toga pravi kopiju elemenata iz clipboarda putem xml serijalizacije
	 * i zatim ih prerađuje tako da budu smešteni relativno u odnosu na centar.
	 * Na kraju ih pakuje u AddCommand-u i šalje na izvršavanje.
	 */
	@SuppressWarnings("unchecked")
	public void actionPerformed(ActionEvent arg0) {
		document = Workspace.getInstance().getActiveDocument();

		if (document == null)
			return;

		x = -((GraphWorkArea) (document.getWorkArea())).getTranslateX();
		y = -((GraphWorkArea) (document.getWorkArea())).getTranslateY();

		Dimension windowSize = GMainFrame.getInstance().getGraphDocumentViewDimension(
				document.getModel());

		x += (windowSize.getWidth() * 0.5)
				/ ((GraphWorkArea) (document.getWorkArea())).getScaling();
		y += (windowSize.getHeight() * 0.5)
				/ ((GraphWorkArea) (document.getWorkArea())).getScaling();

		// Koordinate centra mase pastovanih elemenata
		double centerOfMassX = 0;
		double centerOfMassY = 0;

		for (GraphElement element : Clipboard.getInstance().getCopiedElements()) {
			if (!(element instanceof Link)) {
				centerOfMassX += element.getPosition().getX();
				centerOfMassY += element.getPosition().getY();
			}
		}

		centerOfMassX /= Clipboard.getInstance().getCopiedElements().size();
		centerOfMassY /= Clipboard.getInstance().getCopiedElements().size();

		x -= centerOfMassX;
		y -= centerOfMassY;

		AddCommand newAdd = new AddCommand(true);
		newAdd.setDocument(document);
		List<GraphElement> obrada = null;
		try {
			BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
					"clip.dat"), "UTF8"));
			Clipboard.getInstance().getXstream()
					.toXML(Clipboard.getInstance().getCopiedElements(), out);

			BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(
					"clip.dat")));
			obrada = (List<GraphElement>) Clipboard.getInstance().getXstream().fromXML(in);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		for (GraphElement element : obrada) {
			newAdd.addAddedElements(formPastedElement(element));
		}

		document.getModel().getInvoker().executeCommand(newAdd);
	}

	/**
	 * Metoda zadužena za preradu kopija elemenata tako da budu pozicionirani
	 * relativno u odnosu na centar vizira aktivnog dokumenta.
	 * 
	 * @param element
	 *            grafički element koji je kopiran.
	 * @return prerađen element.
	 */
	private GraphElement formPastedElement(GraphElement element) {
		element.setParent(document.getModel());
		element.setName(element.getName().substring(0, element.getName().length() - 1)
				+ document.getModel().getElementCount());
		if (element instanceof Link) {
			Link link = (Link) element;
			link.getStart()
					.getPosition()
					.setLocation(x + link.getStart().getPosition().getX(),
							y + link.getStart().getPosition().getY());
			link.getEnd()
					.getPosition()
					.setLocation(x + link.getEnd().getPosition().getX(),
							y + link.getEnd().getPosition().getY());
			for (BreakPoint bp : link.getBreakPoints()) {
				bp.getPosition().setLocation(x + bp.getPosition().getX(),
						y + bp.getPosition().getY());
			}
		} else {
			element.getPosition().setLocation(x + element.getPosition().getX(),
					y + element.getPosition().getY());
		}
		return element;
	}
}